#ifndef __NETWORKSOCKET_H__
#define __NETWORKSOCKET_H__



#include "common/Network.h"
#include "Common/Common.h"

namespace SPlayer
{
    namespace Network
    {
        using namespace System;
        using namespace System::Net;
        using namespace System::Net::Sockets;
        using namespace System::Collections::Generic;
        using namespace SPlayer;
        using namespace SPlayer::Common;
        using namespace System::IO;

        ref class NetworkSocketEventDispatcher
        {
        public:
            /*! @brief Asynchronous connect is finished, no metter failed or successed.
             *! use NetworkSocket::Connected property to check whether it is connected or not.
             *! @note Synchronous connect will not emit this signal.*/
            Action ^onConnectionFinished;
        };
        /*! @brief Create a socket which connect to SPlayer's Server
         *! If you want to communicate with SPlayer Server, use
         *! NetworkProcessor.
         *! 
         *! example :
         *! \code c++
         *! public:
         *! NetworkProcessor ^processor;
         *! 
         *! ...
         *! 
         *! auto socket = gcnew NetworkSocket;
         *! if (socket->connect())
         *! {
         *!     processor = gcnew NetworkProcessor(socket);
         *!     processor->eventDispatcher->onDataReceiveFinished +=
         *!         gcnew Action(this, &Xxxx::onReceive);
         *!     
         *!     NetworkParamCollection ^params;
         *!     params->Add("Request", "DownloadFile");
         *!     params->Add("FileName", "song.mp3");
         *!     processor->send();
         *! }
         *! 
         *! void onReceive()
         *! {
         *!     auto filedata = processor->receivedData;
         *!     ...
         *! }
         *! \endcode
         *! 
         *! */
        ref class NetworkSocket : Socket
        {
        public:
            NetworkSocket() : Socket(Sockets::AddressFamily::InterNetwork, Sockets::SocketType::Stream, Sockets::ProtocolType::Tcp)
            {
                ;
            }
        public:
            bool connect()
            {
                try
                {
                    this->Connect(NetworkInfo::hostAddresses, NetworkInfo::port);
                }
                catch (System::Exception ^)
                {
                }
                return this->Connected;
            }
            void connectAsync()
            {
                this->BeginConnect(NetworkInfo::hostAddresses, NetworkInfo::port,
                                   gcnew AsyncCallback(this, &NetworkSocket::onBeginConnect),
                                   nullptr);
            }
        public:
            NetworkSocketEventDispatcher ^eventDispatcher = gcnew NetworkSocketEventDispatcher;
        private:
            void onBeginConnect(System::IAsyncResult^ ar)
            {
                try
                {
                    this->EndConnect(ar);
                }
                catch (System::Exception ^)
                {
                }
                Function::InvokeSync(eventDispatcher->onConnectionFinished);
            }
        };
    }
}
#endif // __NETWORKSOCKET_H__